package com.example.pos_link;

import static android.content.Context.MODE_PRIVATE;

import android.Manifest;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.example.pos_link.pigeon.POSLinkAndroid;
import com.example.pos_link.pigeon.POSLinkBatch;
import com.example.pos_link.pigeon.POSLinkDevice;
import com.example.pos_link.pigeon.POSLinkForm;
import com.example.pos_link.pigeon.POSLinkLogSet;
import com.example.pos_link.pigeon.POSLinkManage;
import com.example.pos_link.pigeon.POSLinkPayload;
import com.example.pos_link.pigeon.POSLinkPed;
import com.example.pos_link.pigeon.POSLinkReport;
import com.example.pos_link.pigeon.POSLinkSet;
import com.example.pos_link.pigeon.POSLinkTransaction;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.pax.gl.commhelper.IBtScanner;
import com.pax.gl.commhelper.impl.PaxGLComm;
import com.pax.poscomm.usb.utils.USBUtil;
import com.pax.poscomm.utils.CommLog;
import com.pax.poscore.LogSetting;
import com.pax.poscore.commsetting.AidlSetting;
import com.pax.poscore.commsetting.BluetoothSetting;
import com.pax.poscore.commsetting.CommunicationSetting;
import com.pax.poscore.commsetting.HttpSetting;
import com.pax.poscore.commsetting.HttpsSetting;
import com.pax.poscore.commsetting.SslSetting;
import com.pax.poscore.commsetting.TcpSetting;
import com.pax.poscore.commsetting.UartSetting;
import com.pax.poscore.commsetting.UsbSetting;
import com.pax.poslinkadmin.ExecutionResult;
import com.pax.poslinkadmin.RawResponse;
import com.pax.poslinkadmin.ReportStatusListener;
import com.pax.poslinkadmin.UploadResult;
import com.pax.poslinkadmin.device.CameraScanRequest;
import com.pax.poslinkadmin.device.CameraScanResponse;
import com.pax.poslinkadmin.device.CardInsertDetectionRequest;
import com.pax.poslinkadmin.device.CardInsertDetectionResponse;
import com.pax.poslinkadmin.device.MifareCardRequest;
import com.pax.poslinkadmin.device.MifareCardResponse;
import com.pax.poslinkadmin.device.PrinterRequest;
import com.pax.poslinkadmin.device.PrinterResponse;
import com.pax.poslinkadmin.form.ClearMessageRequest;
import com.pax.poslinkadmin.form.ClearMessageResponse;
import com.pax.poslinkadmin.form.InputTextRequest;
import com.pax.poslinkadmin.form.InputTextResponse;
import com.pax.poslinkadmin.form.RemoveCardRequest;
import com.pax.poslinkadmin.form.RemoveCardResponse;
import com.pax.poslinkadmin.form.ShowDialogFormRequest;
import com.pax.poslinkadmin.form.ShowDialogFormResponse;
import com.pax.poslinkadmin.form.ShowDialogRequest;
import com.pax.poslinkadmin.form.ShowDialogResponse;
import com.pax.poslinkadmin.form.ShowItemRequest;
import com.pax.poslinkadmin.form.ShowItemResponse;
import com.pax.poslinkadmin.form.ShowMessageCenterRequest;
import com.pax.poslinkadmin.form.ShowMessageCenterResponse;
import com.pax.poslinkadmin.form.ShowMessageRequest;
import com.pax.poslinkadmin.form.ShowMessageResponse;
import com.pax.poslinkadmin.form.ShowTextBoxRequest;
import com.pax.poslinkadmin.form.ShowTextBoxResponse;
import com.pax.poslinkadmin.manage.CheckFileRequest;
import com.pax.poslinkadmin.manage.CheckFileResponse;
import com.pax.poslinkadmin.manage.DeleteImageRequest;
import com.pax.poslinkadmin.manage.DeleteImageResponse;
import com.pax.poslinkadmin.manage.DoSignatureRequest;
import com.pax.poslinkadmin.manage.DoSignatureResponse;
import com.pax.poslinkadmin.manage.GetSafParametersRequest;
import com.pax.poslinkadmin.manage.GetSafParametersResponse;
import com.pax.poslinkadmin.manage.GetSignatureRequest;
import com.pax.poslinkadmin.manage.GetSignatureResponse;
import com.pax.poslinkadmin.manage.GetVariableRequest;
import com.pax.poslinkadmin.manage.GetVariableResponse;
import com.pax.poslinkadmin.manage.InitRequest;
import com.pax.poslinkadmin.manage.InitResponse;
import com.pax.poslinkadmin.manage.InputAccountRequest;
import com.pax.poslinkadmin.manage.InputAccountResponse;
import com.pax.poslinkadmin.manage.RebootRequest;
import com.pax.poslinkadmin.manage.RebootResponse;
import com.pax.poslinkadmin.manage.ReprintRequest;
import com.pax.poslinkadmin.manage.ReprintResponse;
import com.pax.poslinkadmin.manage.ResetMsrRequest;
import com.pax.poslinkadmin.manage.ResetMsrResponse;
import com.pax.poslinkadmin.manage.ResetRequest;
import com.pax.poslinkadmin.manage.ResetResponse;
import com.pax.poslinkadmin.manage.SetApplePayVasParametersRequest;
import com.pax.poslinkadmin.manage.SetApplePayVasParametersResponse;
import com.pax.poslinkadmin.manage.SetGoogleSmartTapParametersRequest;
import com.pax.poslinkadmin.manage.SetGoogleSmartTapParametersResponse;
import com.pax.poslinkadmin.manage.SetSafParametersRequest;
import com.pax.poslinkadmin.manage.SetSafParametersResponse;
import com.pax.poslinkadmin.manage.SetVariableRequest;
import com.pax.poslinkadmin.manage.SetVariableResponse;
import com.pax.poslinkadmin.manage.TokenAdministrativeRequest;
import com.pax.poslinkadmin.manage.TokenAdministrativeResponse;
import com.pax.poslinkadmin.manage.UpdateResourceFileRequest;
import com.pax.poslinkadmin.manage.UpdateResourceFileResponse;
import com.pax.poslinkadmin.manage.VasPushDataRequest;
import com.pax.poslinkadmin.manage.VasPushDataResponse;
import com.pax.poslinkadmin.payload.PayloadRequest;
import com.pax.poslinkadmin.payload.PayloadResponse;
import com.pax.poslinkadmin.ped.GetPedInformationRequest;
import com.pax.poslinkadmin.ped.GetPedInformationResponse;
import com.pax.poslinkadmin.ped.IncreaseKsnRequest;
import com.pax.poslinkadmin.ped.IncreaseKsnResponse;
import com.pax.poslinkadmin.ped.MacCalculationRequest;
import com.pax.poslinkadmin.ped.MacCalculationResponse;
import com.pax.poslinkadmin.ped.SessionKeyInjectionRequest;
import com.pax.poslinkadmin.ped.SessionKeyInjectionResponse;
import com.pax.poslinksemiintegration.POSLinkSemi;
import com.pax.poslinksemiintegration.Terminal;
import com.pax.poslinksemiintegration.batch.BatchClearRequest;
import com.pax.poslinksemiintegration.batch.BatchClearResponse;
import com.pax.poslinksemiintegration.batch.BatchCloseRequest;
import com.pax.poslinksemiintegration.batch.BatchCloseResponse;
import com.pax.poslinksemiintegration.batch.DeleteSafFileRequest;
import com.pax.poslinksemiintegration.batch.DeleteSafFileResponse;
import com.pax.poslinksemiintegration.batch.DeleteTransactionRequest;
import com.pax.poslinksemiintegration.batch.DeleteTransactionResponse;
import com.pax.poslinksemiintegration.batch.ForceBatchCloseRequest;
import com.pax.poslinksemiintegration.batch.ForceBatchCloseResponse;
import com.pax.poslinksemiintegration.batch.PurgeBatchRequest;
import com.pax.poslinksemiintegration.batch.PurgeBatchResponse;
import com.pax.poslinksemiintegration.batch.SafUploadRequest;
import com.pax.poslinksemiintegration.batch.SafUploadResponse;
import com.pax.poslinksemiintegration.report.HistoryReportRequest;
import com.pax.poslinksemiintegration.report.HistoryReportResponse;
import com.pax.poslinksemiintegration.report.HostDetailReportRequest;
import com.pax.poslinksemiintegration.report.HostDetailReportResponse;
import com.pax.poslinksemiintegration.report.HostReportRequest;
import com.pax.poslinksemiintegration.report.HostReportResponse;
import com.pax.poslinksemiintegration.report.LocalDetailReportRequest;
import com.pax.poslinksemiintegration.report.LocalDetailReportResponse;
import com.pax.poslinksemiintegration.report.LocalFailedReportRequest;
import com.pax.poslinksemiintegration.report.LocalFailedReportResponse;
import com.pax.poslinksemiintegration.report.LocalTotalReportRequest;
import com.pax.poslinksemiintegration.report.LocalTotalReportResponse;
import com.pax.poslinksemiintegration.report.SafSummaryReportRequest;
import com.pax.poslinksemiintegration.report.SafSummaryReportResponse;
import com.pax.poslinksemiintegration.transaction.DoCashRequest;
import com.pax.poslinksemiintegration.transaction.DoCashResponse;
import com.pax.poslinksemiintegration.transaction.DoCheckRequest;
import com.pax.poslinksemiintegration.transaction.DoCheckResponse;
import com.pax.poslinksemiintegration.transaction.DoCreditRequest;
import com.pax.poslinksemiintegration.transaction.DoCreditResponse;
import com.pax.poslinksemiintegration.transaction.DoDebitRequest;
import com.pax.poslinksemiintegration.transaction.DoDebitResponse;
import com.pax.poslinksemiintegration.transaction.DoEbtRequest;
import com.pax.poslinksemiintegration.transaction.DoEbtResponse;
import com.pax.poslinksemiintegration.transaction.DoGiftRequest;
import com.pax.poslinksemiintegration.transaction.DoGiftResponse;
import com.pax.poslinksemiintegration.transaction.DoLoyaltyRequest;
import com.pax.poslinksemiintegration.transaction.DoLoyaltyResponse;
import com.pax.serialport.SerialPortFinderPax;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import io.flutter.app.FlutterActivityEvents;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;

/** PosLinkPlugin */
public class PosLinkPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware, FlutterActivityEvents {
  /// The MethodChannel that will the communication between Flutter and native Android
  ///
  /// This local reference serves to register the plugin with the Flutter Engine and unregister it
  /// when the Flutter Engine is detached from the Activity
  static final String SPF = "SETTING_SPF";
  private Activity currentActivity = new Activity();
  private MethodChannel channel;
  private Context context;
  private BinaryMessenger binaryMessenger;
  static final int PERMISSION_REQUEST = 1001;
  Terminal terminal;
  CommunicationSetting commSetting;
  private List<String> permissions;

  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
    context = flutterPluginBinding.getApplicationContext();
    binaryMessenger = flutterPluginBinding.getBinaryMessenger();
    channel = new MethodChannel(binaryMessenger, "pos_link");
    channel.setMethodCallHandler(this);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
      String[] array = {
              Manifest.permission.INTERNET,
              Manifest.permission.BLUETOOTH,
              Manifest.permission.BLUETOOTH_ADMIN,
              Manifest.permission.BLUETOOTH_SCAN,
              Manifest.permission.BLUETOOTH_CONNECT,
              Manifest.permission.ACCESS_COARSE_LOCATION,
              Manifest.permission.ACCESS_FINE_LOCATION,
              Manifest.permission.READ_EXTERNAL_STORAGE,
              Manifest.permission.WRITE_EXTERNAL_STORAGE,
      };
      permissions = Arrays.asList(array);
    }else {
      String[] array = {
              Manifest.permission.INTERNET,
              Manifest.permission.BLUETOOTH,
              Manifest.permission.BLUETOOTH_ADMIN,
              Manifest.permission.ACCESS_COARSE_LOCATION,
              Manifest.permission.ACCESS_FINE_LOCATION,
              Manifest.permission.READ_EXTERNAL_STORAGE,
              Manifest.permission.WRITE_EXTERNAL_STORAGE,
      };
      permissions = Arrays.asList(array);
    }
  }

  @Override
  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
    switch (call.method) {
      case "permissionAllowed":
        isPermissionAllowed(result);
        break;
      case "configureFlutterEngine":
        configureFlutterEngine(binaryMessenger);
        break;
    }
  }

  @Override
  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
    channel.setMethodCallHandler(null);
  }

  @Override
  public boolean onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if (requestCode == PERMISSION_REQUEST) {
      for (int result : grantResults) {
        if (result != PackageManager.PERMISSION_GRANTED) {
          Toast.makeText(context, "Permission not granted!", Toast.LENGTH_SHORT).show();
          throw new RuntimeException("Permission not granted!");
        }
      }
    }
    return true;
  }

  public void isPermissionAllowed(Result result){
    SharedPreferences sharedPreferences = context.getSharedPreferences(SPF, MODE_PRIVATE);
    LogSetting logSetting = new LogSetting();
    logSetting.setEnable(sharedPreferences.getBoolean("LOG_ENABLE", true));
    logSetting.setLevel(LogSetting.LogLevel.values()[sharedPreferences.getInt("LOG_LEVEL", 1)]);
    logSetting.setDays(sharedPreferences.getInt("LOG_DAYS", 30));
    logSetting.setFileName(sharedPreferences.getString("LOG_FILE_NAME", "POSLog"));
    logSetting.setFilePath(sharedPreferences.getString("LOG_FILE_PATH", ""));
    POSLinkSemi.getInstance().setLogSetting(logSetting);
    commSetting = new AidlSetting();
    List<Integer> permissionStatus = new ArrayList<>();
    List<Boolean> cannotAskPermissions = new ArrayList<>();
    for (String item : permissions) {
      permissionStatus.add(ContextCompat.checkSelfPermission(currentActivity, item));
      cannotAskPermissions.add(ActivityCompat.shouldShowRequestPermissionRationale(currentActivity, item));
    }
    if (!permissionStatus.contains(PackageManager.PERMISSION_DENIED)) {
      return;
    }
    if (cannotAskPermissions.contains(true)) {
      return;
    }
    ActivityCompat.requestPermissions(currentActivity, (String[]) permissions.toArray(), PERMISSION_REQUEST);
    final LocationManager locationManager =
            (LocationManager) currentActivity.getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
    boolean gpsEnabled = false;
    try {
      gpsEnabled = locationManager != null &&
              locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
    } catch (Exception exception) {
    }
    result.success(gpsEnabled);
  }

  @Override
  public void onCreate(Bundle bundle) {

  }

  @Override
  public void onNewIntent(Intent intent) {

  }

  @Override
  public void onPause() {

  }

  @Override
  public void onStart() {

  }

  @Override
  public void onResume() {
    //Adaption for A920 5.1.1, while some payment app change the visibility of navigation bar will cause display issue.
    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP_MR1 && Build.MODEL.equalsIgnoreCase("A920")) {
      ViewGroup contentView = (ViewGroup) ((ViewGroup) currentActivity.findViewById(android.R.id.content)).getChildAt(0);
      contentView.setFitsSystemWindows(true);
      contentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
    }
  }

  @Override
  public void onPostResume() {

  }

  @Override
  public void onDestroy() {

  }

  @Override
  public void onStop() {

  }

  @Override
  public boolean onBackPressed() {
    return false;
  }

  @Override
  public void onUserLeaveHint() {

  }

  @Override
  public void onTrimMemory(int i) {

  }

  @Override
  public void onConfigurationChanged(@NonNull Configuration configuration) {

  }

  @Override
  public void onLowMemory() {

  }

  @Override
  public boolean onActivityResult(int i, int i1, @Nullable Intent intent) {
    return false;
  }

  @Override
  public void onAttachedToActivity(@NonNull ActivityPluginBinding activityPluginBinding) {
    currentActivity = activityPluginBinding.getActivity();
    activityPluginBinding.addRequestPermissionsResultListener(this);
  }

  @Override
  public void onDetachedFromActivityForConfigChanges() {
    currentActivity = null;
  }

  @Override
  public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding activityPluginBinding) {
    currentActivity = activityPluginBinding.getActivity();
  }

  @Override
  public void onDetachedFromActivity() {

  }


  public void configureFlutterEngine(@NonNull BinaryMessenger binaryMessenger) {

    POSLinkSet.POSLinkSetApi.setup(binaryMessenger, new POSLinkSet.POSLinkSetApi() {
      @Override
      public void setAIDLSetting() {
        AidlSetting aidlSetting = new AidlSetting();
        if (!aidlSetting.equals(commSetting) && terminal != null) {
          POSLinkSemi.getInstance().removeTerminal(terminal);
        }
        commSetting = aidlSetting;
      }

      @Override
      public void setTCPSetting(POSLinkSet.TCPSetting setting) {
        TcpSetting tcpSetting = new TcpSetting(setting.getIp(), setting.getPort(), setting.getTimeout().intValue());
        if (!tcpSetting.equals(commSetting) && terminal != null) {
          POSLinkSemi.getInstance().removeTerminal(terminal);
        }
        commSetting = tcpSetting;
      }

      @Override
      public void setHttpSetting(POSLinkSet.HttpSetting setting) {
        HttpSetting httpSetting = new HttpSetting(setting.getIp(), setting.getPort(), setting.getTimeout().intValue());
        if (!httpSetting.equals(commSetting) && terminal != null) {
          POSLinkSemi.getInstance().removeTerminal(terminal);
        }
        commSetting = httpSetting;
      }

      @Override
      public void setHttpsSetting(POSLinkSet.HttpsSetting setting) {
        HttpsSetting httpsSetting = new HttpsSetting(setting.getIp(), setting.getPort(), setting.getTimeout().intValue());
        if (!httpsSetting.equals(commSetting) && terminal != null) {
          POSLinkSemi.getInstance().removeTerminal(terminal);
        }
        commSetting = httpsSetting;
      }

      @Override
      public void setSslSetting(POSLinkSet.SslSetting setting) {
        SslSetting sslSetting = new SslSetting(setting.getIp(), setting.getPort(), setting.getTimeout().intValue());
        if (!sslSetting.equals(commSetting) && terminal != null) {
          POSLinkSemi.getInstance().removeTerminal(terminal);
        }
        commSetting = sslSetting;
      }

      @Override
      public void setUsbSetting(POSLinkSet.UsbSetting setting) {
        UsbSetting usbSetting = new UsbSetting();
        usbSetting.setTimeout(setting.getTimeout().intValue());
        if (!usbSetting.equals(commSetting) && terminal != null) {
          POSLinkSemi.getInstance().removeTerminal(terminal);
        }
        commSetting = usbSetting;
        USBUtil.requestUSBPermissionIfNeed(context);
      }

      @Override
      public void setUartSetting(POSLinkSet.UartSetting setting) {
        UartSetting uartSetting = new UartSetting(setting.getSerialPort(), setting.getBaudRate(), setting.getTimeout().intValue());
        if (!uartSetting.equals(commSetting) && terminal != null) {
          POSLinkSemi.getInstance().removeTerminal(terminal);
        }
        commSetting = uartSetting;
      }

      @Override
      public List<String> getUartDevices() {
        List<String> devices = new ArrayList<>();
        SerialPortFinderPax serialPortFinderPax = new SerialPortFinderPax();
        String[] devicesPathList = serialPortFinderPax.getAllDevicesPath();
        for (String path : devicesPathList) {
          if (path.startsWith("/dev/tty")) {
            devices.add(path);
          }
        }
        return devices;
      }

      @Override
      public void setBTSetting(@NonNull POSLinkSet.BTSetting setting) {
        BluetoothSetting bluetoothSetting = new BluetoothSetting();
        bluetoothSetting.setTimeout(setting.getTimeout().intValue());
        bluetoothSetting.setMacAddr(setting.getMacAddr());

        if (!bluetoothSetting.equals(commSetting) && terminal != null) {
          POSLinkSemi.getInstance().removeTerminal(terminal);
        }

        commSetting = bluetoothSetting;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
          String[] permissions = new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION};
          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            permissions = new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION,
                    Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT};
          }
          currentActivity.requestPermissions(permissions, PERMISSION_REQUEST);
        }
      }

      @Override
      public void cancel() {
        if (terminal != null) {
          terminal.cancel();
        }
      }

      @Override
      public void handshake(POSLinkSet.Result<Boolean> result) {
        if (commSetting != null) {
          new Thread(new Runnable() {
            @Override
            public void run() {
              terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
              if (terminal != null) {
                result.success(true);
              } else {
                result.success(false);
              }
            }
          }).start();
        }
      }

      @Override
      public void remove() {
        if (terminal != null) {
          POSLinkSemi.getInstance().removeTerminal(terminal);
          terminal = null;
        }
      }
    });

    POSLinkLogSet.POSLinkLogSetApi.setup(binaryMessenger, new POSLinkLogSet.POSLinkLogSetApi() {
      @Override
      public void setLogSetting(POSLinkLogSet.LogSetting setting) {
        POSLinkSemi.getInstance().getLogSetting().setEnable(setting.getEnable());
        POSLinkSemi.getInstance().getLogSetting().setLevel(setting.getLevel() == POSLinkLogSet.LogLevel.DEBUG ?
                LogSetting.LogLevel.DEBUG : LogSetting.LogLevel.ERROR);
        POSLinkSemi.getInstance().getLogSetting().setDays(setting.getDays().intValue());
        POSLinkSemi.getInstance().getLogSetting().setFileName(setting.getFileName());
        POSLinkSemi.getInstance().getLogSetting().setFilePath(setting.getFilePath());
        SharedPreferences sharedPreferences = context.getSharedPreferences(SPF, MODE_PRIVATE);
        SharedPreferences.Editor editor = sharedPreferences.edit();
        editor.putBoolean("LOG_ENABLE", setting.getEnable());
        editor.putInt("LOG_LEVEL", setting.getLevel().ordinal());
        editor.putInt("LOG_DAYS", setting.getDays().intValue());
        editor.putString("LOG_FILE_NAME", setting.getFileName());
        editor.putString("LOG_FILE_PATH", setting.getFilePath());
        editor.apply();
      }

      @Override
      public void upload(POSLinkLogSet.Result<POSLinkLogSet.UploadResult> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkLogSet.UploadResult uploadResult = new POSLinkLogSet.UploadResult();
            uploadResult.setPosLinkUploadErrorCode("Init Failed");
            result.success(uploadResult);
            return;
          }
          UploadResult uploadResult = terminal.uploadLog(null);
          POSLinkLogSet.UploadResult rsp = jsonTransform(uploadResult, POSLinkLogSet.UploadResult.class);
          currentActivity.runOnUiThread(() -> result.success(rsp));
        }).start();
      }
    });

    POSLinkAndroid.POSLinkAndroidApi.setup(binaryMessenger, new POSLinkAndroid.POSLinkAndroidApi() {
      IBtScanner btScan;
      List<POSLinkAndroid.BluetoothDevice> deviceList = new ArrayList<>();

      @NonNull
      @Override
      public Boolean checkBluetoothEnable() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
          String[] permissions = new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION};
          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            permissions = new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION,
                    Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT};
          }
          currentActivity.requestPermissions(permissions, PERMISSION_REQUEST);
        }

        BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
        if (!btAdapter.isEnabled()) {
          if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || ActivityCompat.checkSelfPermission(currentActivity, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED) {
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            currentActivity.startActivity(intent);
          }
          return false;
        }
        return true;
      }

      @NonNull
      @Override
      public Boolean startSearchBluetooth() {
        if (btScan == null) {
          btScan = PaxGLComm.getInstance(context.getApplicationContext()).getBtScanner();
        }
        deviceList.clear();
        btScan.start(new IBtScanner.IBtScannerListener() {
          @Override
          public void onDiscovered(IBtScanner.IBtDevice iBtDevice) {
            POSLinkAndroid.BluetoothDevice device = new POSLinkAndroid.BluetoothDevice();
            device.setName(iBtDevice.getName());
            device.setMac(iBtDevice.getIdentifier());
            deviceList.add(device);
          }

          @Override
          public void onFinished() {

          }
        }, 1000);
        return true;
      }

      @NonNull
      @Override
      public Boolean stopSearchBluetooth() {
        if (btScan != null) {
          btScan.stop();
        }
        deviceList.clear();
        return true;
      }

      @NonNull
      @Override
      public List<POSLinkAndroid.BluetoothDevice> getBluetoothDeviceList() {
        return deviceList;
      }

      @Override
      public void sendRawCommand(@NonNull String command, POSLinkAndroid.Result<POSLinkAndroid.RawResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkAndroid.RawResponse rsp = new POSLinkAndroid.RawResponse();
            rsp.setIsSuccess(false);
            rsp.setMessage("Init Failed");
            result.success(rsp);
          } else {
            String rawCommand = formatRawFromHex(command);
            RawResponse response = terminal.sendRawCommand(rawCommand);
            POSLinkAndroid.RawResponse rsp = new POSLinkAndroid.RawResponse();
            rsp.setIsSuccess(response.isSuccessful());
            rsp.setMessage(response.message());
            String responseStr = response.response();
            if (!TextUtils.isEmpty(responseStr)) {
              responseStr = CommLog.getHexString(response.response());
            }
            rsp.setResponse(responseStr);
            result.success(rsp);
          }
        }).start();
      }

      private String formatRawFromHex(String hex) {
        for (int i = 0; i <= 256; i++) {
          String s = Integer.toHexString(i).toLowerCase();
          if (i <= 10) {
            s = "0" + s;
          }
          char c = (char) Integer.parseInt(s, 16);
          hex = hex.replace("[" + s + "]", c + "");
        }
        return hex;
      }


    });

    POSLinkDevice.POSLinkDeviceApi.setup(binaryMessenger, new POSLinkDevice.POSLinkDeviceApi() {
      @Override
      public void printer(@NonNull POSLinkDevice.DevicePrinterRequest req, POSLinkDevice.Result<POSLinkDevice.DevicePrinterResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkDevice.DevicePrinterResponse rsp = new POSLinkDevice.DevicePrinterResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          PrinterRequest printerRequest = jsonTransform(req, PrinterRequest.class);
          ExecutionResult<PrinterResponse> executionResult = terminal.getDevice().printer(printerRequest);
          POSLinkDevice.DevicePrinterResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkDevice.DevicePrinterResponse.class);
          } else {
            rsp = new POSLinkDevice.DevicePrinterResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void mifareCard(@NonNull POSLinkDevice.DeviceMifareCardRequest req, POSLinkDevice.Result<POSLinkDevice.DeviceMifareCardResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkDevice.DeviceMifareCardResponse rsp = new POSLinkDevice.DeviceMifareCardResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          MifareCardRequest mifareCardRequest = jsonTransform(req, MifareCardRequest.class);
          ExecutionResult<MifareCardResponse> executionResult = terminal.getDevice().mifareCard(mifareCardRequest);
          POSLinkDevice.DeviceMifareCardResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkDevice.DeviceMifareCardResponse.class);
          } else {
            rsp = new POSLinkDevice.DeviceMifareCardResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void cameraScan(@NonNull POSLinkDevice.DeviceCameraScanRequest req, POSLinkDevice.Result<POSLinkDevice.DeviceCameraScanResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkDevice.DeviceCameraScanResponse rsp = new POSLinkDevice.DeviceCameraScanResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          CameraScanRequest cameraScanRequest = jsonTransform(req, CameraScanRequest.class);
          ExecutionResult<CameraScanResponse> executionResult = terminal.getDevice().cameraScan(cameraScanRequest);
          POSLinkDevice.DeviceCameraScanResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkDevice.DeviceCameraScanResponse.class);
          } else {
            rsp = new POSLinkDevice.DeviceCameraScanResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void cardInsertDetection(@NonNull POSLinkDevice.DeviceCardInsertDetectionRequest req, POSLinkDevice.Result<POSLinkDevice.DeviceCardInsertDetectionResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkDevice.DeviceCardInsertDetectionResponse rsp = new POSLinkDevice.DeviceCardInsertDetectionResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          CardInsertDetectionRequest cardInsertDetectionRequest = jsonTransform(req, CardInsertDetectionRequest.class);
          ExecutionResult<CardInsertDetectionResponse> executionResult = terminal.getDevice().cardInsertDetection(cardInsertDetectionRequest);
          POSLinkDevice.DeviceCardInsertDetectionResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkDevice.DeviceCardInsertDetectionResponse.class);
          } else {
            rsp = new POSLinkDevice.DeviceCardInsertDetectionResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }
    });

    POSLinkForm.POSLinkFormApi.setup(binaryMessenger, new POSLinkForm.POSLinkFormApi() {
      @Override
      public void showDialog(@NonNull POSLinkForm.FormShowDialogRequest req, POSLinkForm.Result<POSLinkForm.FormShowDialogResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkForm.FormShowDialogResponse rsp = new POSLinkForm.FormShowDialogResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          ShowDialogRequest showDialogRequest = jsonTransform(req, ShowDialogRequest.class);
          ExecutionResult<ShowDialogResponse> executionResult = terminal.getForm().showDialog(showDialogRequest);
          POSLinkForm.FormShowDialogResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkForm.FormShowDialogResponse.class);
          } else {
            rsp = new POSLinkForm.FormShowDialogResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void showTextBox(@NonNull POSLinkForm.FormShowTextBoxRequest req, POSLinkForm.Result<POSLinkForm.FormShowTextBoxResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkForm.FormShowTextBoxResponse rsp = new POSLinkForm.FormShowTextBoxResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          ShowTextBoxRequest showTextBoxRequest = jsonTransform(req, ShowTextBoxRequest.class);
          ExecutionResult<ShowTextBoxResponse> executionResult = terminal.getForm().showTextBox(showTextBoxRequest);
          POSLinkForm.FormShowTextBoxResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkForm.FormShowTextBoxResponse.class);
          } else {
            rsp = new POSLinkForm.FormShowTextBoxResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void showMessageCenter(@NonNull POSLinkForm.FormShowMessageCenterRequest req, POSLinkForm.Result<POSLinkForm.FormShowMessageCenterResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkForm.FormShowMessageCenterResponse rsp = new POSLinkForm.FormShowMessageCenterResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          ShowMessageCenterRequest showMessageCenterRequest = jsonTransform(req, ShowMessageCenterRequest.class);
          ExecutionResult<ShowMessageCenterResponse> executionResult = terminal.getForm().showMessageCenter(showMessageCenterRequest);
          POSLinkForm.FormShowMessageCenterResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkForm.FormShowMessageCenterResponse.class);
          } else {
            rsp = new POSLinkForm.FormShowMessageCenterResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void showItem(@NonNull POSLinkForm.FormShowItemRequest req, POSLinkForm.Result<POSLinkForm.FormShowItemResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkForm.FormShowItemResponse rsp = new POSLinkForm.FormShowItemResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          ShowItemRequest showItemRequest = jsonTransform(req, ShowItemRequest.class);
          ExecutionResult<ShowItemResponse> executionResult = terminal.getForm().showItem(showItemRequest);
          POSLinkForm.FormShowItemResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkForm.FormShowItemResponse.class);
          } else {
            rsp = new POSLinkForm.FormShowItemResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void clearMessage(@NonNull POSLinkForm.FormClearMessageRequest req, POSLinkForm.Result<POSLinkForm.FormClearMessageResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkForm.FormClearMessageResponse rsp = new POSLinkForm.FormClearMessageResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          ClearMessageRequest clearMessageRequest = jsonTransform(req, ClearMessageRequest.class);
          ExecutionResult<ClearMessageResponse> executionResult = terminal.getForm().clearMessage(clearMessageRequest);
          POSLinkForm.FormClearMessageResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkForm.FormClearMessageResponse.class);
          } else {
            rsp = new POSLinkForm.FormClearMessageResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void showDialogForm(@NonNull POSLinkForm.FormShowDialogFormRequest req, POSLinkForm.Result<POSLinkForm.FormShowDialogFormResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkForm.FormShowDialogFormResponse rsp = new POSLinkForm.FormShowDialogFormResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          ShowDialogFormRequest showDialogFormRequest = jsonTransform(req, ShowDialogFormRequest.class);
          ExecutionResult<ShowDialogFormResponse> executionResult = terminal.getForm().showDialogForm(showDialogFormRequest);
          POSLinkForm.FormShowDialogFormResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkForm.FormShowDialogFormResponse.class);
          } else {
            rsp = new POSLinkForm.FormShowDialogFormResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void removeCard(@NonNull POSLinkForm.FormRemoveCardRequest req, POSLinkForm.Result<POSLinkForm.FormRemoveCardResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkForm.FormRemoveCardResponse rsp = new POSLinkForm.FormRemoveCardResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          RemoveCardRequest removeCardRequest = jsonTransform(req, RemoveCardRequest.class);
          ExecutionResult<RemoveCardResponse> executionResult = terminal.getForm().removeCard(removeCardRequest);
          POSLinkForm.FormRemoveCardResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkForm.FormRemoveCardResponse.class);
          } else {
            rsp = new POSLinkForm.FormRemoveCardResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void inputText(@NonNull POSLinkForm.FormInputTextRequest req, POSLinkForm.Result<POSLinkForm.FormInputTextResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkForm.FormInputTextResponse rsp = new POSLinkForm.FormInputTextResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          InputTextRequest inputTextRequest = jsonTransform(req, InputTextRequest.class);
          ExecutionResult<InputTextResponse> executionResult = terminal.getForm().inputText(inputTextRequest);
          POSLinkForm.FormInputTextResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkForm.FormInputTextResponse.class);
          } else {
            rsp = new POSLinkForm.FormInputTextResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void showMessage(@NonNull POSLinkForm.FormShowMessageRequest req, POSLinkForm.Result<POSLinkForm.FormShowMessageResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkForm.FormShowMessageResponse rsp = new POSLinkForm.FormShowMessageResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          ShowMessageRequest showMessageRequest = jsonTransform(req, ShowMessageRequest.class);
          ExecutionResult<ShowMessageResponse> executionResult = terminal.getForm().showMessage(showMessageRequest);
          POSLinkForm.FormShowMessageResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkForm.FormShowMessageResponse.class);
          } else {
            rsp = new POSLinkForm.FormShowMessageResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }
    });

    POSLinkManage.POSLinkManageApi.setup(binaryMessenger, new POSLinkManage.POSLinkManageApi() {
      @Override
      public void deleteImage(@NonNull POSLinkManage.ManageDeleteImageRequest req, POSLinkManage.Result<POSLinkManage.ManageDeleteImageResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkManage.ManageDeleteImageResponse rsp = new POSLinkManage.ManageDeleteImageResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          DeleteImageRequest deleteImageRequest = jsonTransform(req, DeleteImageRequest.class);
          ExecutionResult<DeleteImageResponse> executionResult = terminal.getManage().deleteImage(deleteImageRequest);
          POSLinkManage.ManageDeleteImageResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkManage.ManageDeleteImageResponse.class);
          } else {
            rsp = new POSLinkManage.ManageDeleteImageResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void getSafParameters(@NonNull POSLinkManage.ManageGetSafParametersRequest req, POSLinkManage.Result<POSLinkManage.ManageGetSafParametersResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkManage.ManageGetSafParametersResponse rsp = new POSLinkManage.ManageGetSafParametersResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          GetSafParametersRequest getSafParametersRequest = jsonTransform(req, GetSafParametersRequest.class);
          ExecutionResult<GetSafParametersResponse> executionResult = terminal.getManage().getSafParameters();
          POSLinkManage.ManageGetSafParametersResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkManage.ManageGetSafParametersResponse.class);
          } else {
            rsp = new POSLinkManage.ManageGetSafParametersResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void resetMsr(@NonNull POSLinkManage.ManageResetMsrRequest req, POSLinkManage.Result<POSLinkManage.ManageResetMsrResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkManage.ManageResetMsrResponse rsp = new POSLinkManage.ManageResetMsrResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          ResetMsrRequest resetMsrRequest = jsonTransform(req, ResetMsrRequest.class);
          ExecutionResult<ResetMsrResponse> executionResult = terminal.getManage().resetMsr();
          POSLinkManage.ManageResetMsrResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkManage.ManageResetMsrResponse.class);
          } else {
            rsp = new POSLinkManage.ManageResetMsrResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void doSignature(@NonNull POSLinkManage.ManageDoSignatureRequest req, POSLinkManage.Result<POSLinkManage.ManageDoSignatureResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkManage.ManageDoSignatureResponse rsp = new POSLinkManage.ManageDoSignatureResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          DoSignatureRequest doSignatureRequest = jsonTransform(req, DoSignatureRequest.class);
          ExecutionResult<DoSignatureResponse> executionResult = terminal.getManage().doSignature(doSignatureRequest);
          POSLinkManage.ManageDoSignatureResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkManage.ManageDoSignatureResponse.class);
          } else {
            rsp = new POSLinkManage.ManageDoSignatureResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void reboot(@NonNull POSLinkManage.ManageRebootRequest req, POSLinkManage.Result<POSLinkManage.ManageRebootResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkManage.ManageRebootResponse rsp = new POSLinkManage.ManageRebootResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          RebootRequest rebootRequest = jsonTransform(req, RebootRequest.class);
          ExecutionResult<RebootResponse> executionResult = terminal.getManage().reboot();
          POSLinkManage.ManageRebootResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkManage.ManageRebootResponse.class);
          } else {
            rsp = new POSLinkManage.ManageRebootResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void init(@NonNull POSLinkManage.ManageInitRequest req, POSLinkManage.Result<POSLinkManage.ManageInitResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkManage.ManageInitResponse rsp = new POSLinkManage.ManageInitResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          InitRequest initRequest = jsonTransform(req, InitRequest.class);
          ExecutionResult<InitResponse> executionResult = terminal.getManage().init();
          POSLinkManage.ManageInitResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkManage.ManageInitResponse.class);
          } else {
            rsp = new POSLinkManage.ManageInitResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void checkFile(@NonNull POSLinkManage.ManageCheckFileRequest req, POSLinkManage.Result<POSLinkManage.ManageCheckFileResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkManage.ManageCheckFileResponse rsp = new POSLinkManage.ManageCheckFileResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          CheckFileRequest checkFileRequest = jsonTransform(req, CheckFileRequest.class);
          ExecutionResult<CheckFileResponse> executionResult = terminal.getManage().checkFile(checkFileRequest);
          POSLinkManage.ManageCheckFileResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkManage.ManageCheckFileResponse.class);
          } else {
            rsp = new POSLinkManage.ManageCheckFileResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void tokenAdministrative(@NonNull POSLinkManage.ManageTokenAdministrativeRequest req, POSLinkManage.Result<POSLinkManage.ManageTokenAdministrativeResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkManage.ManageTokenAdministrativeResponse rsp = new POSLinkManage.ManageTokenAdministrativeResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          TokenAdministrativeRequest tokenAdministrativeRequest = jsonTransform(req, TokenAdministrativeRequest.class);
          ExecutionResult<TokenAdministrativeResponse> executionResult = terminal.getManage().tokenAdministrative(tokenAdministrativeRequest);
          POSLinkManage.ManageTokenAdministrativeResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkManage.ManageTokenAdministrativeResponse.class);
          } else {
            rsp = new POSLinkManage.ManageTokenAdministrativeResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void reprint(@NonNull POSLinkManage.ManageReprintRequest req, POSLinkManage.Result<POSLinkManage.ManageReprintResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkManage.ManageReprintResponse rsp = new POSLinkManage.ManageReprintResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          ReprintRequest reprintRequest = jsonTransform(req, ReprintRequest.class);
          ExecutionResult<ReprintResponse> executionResult = terminal.getManage().reprint(reprintRequest);
          POSLinkManage.ManageReprintResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkManage.ManageReprintResponse.class);
          } else {
            rsp = new POSLinkManage.ManageReprintResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void vasPushData(@NonNull POSLinkManage.ManageVasPushDataRequest req, POSLinkManage.Result<POSLinkManage.ManageVasPushDataResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkManage.ManageVasPushDataResponse rsp = new POSLinkManage.ManageVasPushDataResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          VasPushDataRequest vasPushDataRequest = jsonTransform(req, VasPushDataRequest.class);
          ExecutionResult<VasPushDataResponse> executionResult = terminal.getManage().vasPushData(vasPushDataRequest);
          POSLinkManage.ManageVasPushDataResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkManage.ManageVasPushDataResponse.class);
          } else {
            rsp = new POSLinkManage.ManageVasPushDataResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void setApplePayVasParameters(@NonNull POSLinkManage.ManageSetApplePayVasParametersRequest req, POSLinkManage.Result<POSLinkManage.ManageSetApplePayVasParametersResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkManage.ManageSetApplePayVasParametersResponse rsp = new POSLinkManage.ManageSetApplePayVasParametersResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          SetApplePayVasParametersRequest setApplePayVasParametersRequest = jsonTransform(req, SetApplePayVasParametersRequest.class);
          ExecutionResult<SetApplePayVasParametersResponse> executionResult = terminal.getManage().setApplePayVasParameters(setApplePayVasParametersRequest);
          POSLinkManage.ManageSetApplePayVasParametersResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkManage.ManageSetApplePayVasParametersResponse.class);
          } else {
            rsp = new POSLinkManage.ManageSetApplePayVasParametersResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void setGoogleSmartTapParameters(@NonNull POSLinkManage.ManageSetGoogleSmartTapParametersRequest req, POSLinkManage.Result<POSLinkManage.ManageSetGoogleSmartTapParametersResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkManage.ManageSetGoogleSmartTapParametersResponse rsp = new POSLinkManage.ManageSetGoogleSmartTapParametersResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          SetGoogleSmartTapParametersRequest setGoogleSmartTapParametersRequest = jsonTransform(req, SetGoogleSmartTapParametersRequest.class);
          ExecutionResult<SetGoogleSmartTapParametersResponse> executionResult = terminal.getManage().setGoogleSmartTapParameters(setGoogleSmartTapParametersRequest);
          POSLinkManage.ManageSetGoogleSmartTapParametersResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkManage.ManageSetGoogleSmartTapParametersResponse.class);
          } else {
            rsp = new POSLinkManage.ManageSetGoogleSmartTapParametersResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void reset(@NonNull POSLinkManage.ManageResetRequest req, POSLinkManage.Result<POSLinkManage.ManageResetResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkManage.ManageResetResponse rsp = new POSLinkManage.ManageResetResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          ResetRequest resetRequest = jsonTransform(req, ResetRequest.class);
          ExecutionResult<ResetResponse> executionResult = terminal.getManage().reset();
          POSLinkManage.ManageResetResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkManage.ManageResetResponse.class);
          } else {
            rsp = new POSLinkManage.ManageResetResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void getSignature(@NonNull POSLinkManage.ManageGetSignatureRequest req, POSLinkManage.Result<POSLinkManage.ManageGetSignatureResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkManage.ManageGetSignatureResponse rsp = new POSLinkManage.ManageGetSignatureResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          GetSignatureRequest getSignatureRequest = jsonTransform(req, GetSignatureRequest.class);
          ExecutionResult<GetSignatureResponse> executionResult = terminal.getManage().getSignature();
          POSLinkManage.ManageGetSignatureResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkManage.ManageGetSignatureResponse.class);
          } else {
            rsp = new POSLinkManage.ManageGetSignatureResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void updateResourceFile(@NonNull POSLinkManage.ManageUpdateResourceFileRequest req, POSLinkManage.Result<POSLinkManage.ManageUpdateResourceFileResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkManage.ManageUpdateResourceFileResponse rsp = new POSLinkManage.ManageUpdateResourceFileResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          UpdateResourceFileRequest updateResourceFileRequest = jsonTransform(req, UpdateResourceFileRequest.class);
          ExecutionResult<UpdateResourceFileResponse> executionResult = terminal.getManage().updateResourceFile(updateResourceFileRequest);
          POSLinkManage.ManageUpdateResourceFileResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkManage.ManageUpdateResourceFileResponse.class);
          } else {
            rsp = new POSLinkManage.ManageUpdateResourceFileResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void setSafParameters(@NonNull POSLinkManage.ManageSetSafParametersRequest req, POSLinkManage.Result<POSLinkManage.ManageSetSafParametersResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkManage.ManageSetSafParametersResponse rsp = new POSLinkManage.ManageSetSafParametersResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          SetSafParametersRequest setSafParametersRequest = jsonTransform(req, SetSafParametersRequest.class);
          ExecutionResult<SetSafParametersResponse> executionResult = terminal.getManage().setSafParameters(setSafParametersRequest);
          POSLinkManage.ManageSetSafParametersResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkManage.ManageSetSafParametersResponse.class);
          } else {
            rsp = new POSLinkManage.ManageSetSafParametersResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void setVariable(@NonNull POSLinkManage.ManageSetVariableRequest req, POSLinkManage.Result<POSLinkManage.ManageSetVariableResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkManage.ManageSetVariableResponse rsp = new POSLinkManage.ManageSetVariableResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          SetVariableRequest setVariableRequest = jsonTransform(req, SetVariableRequest.class);
          ExecutionResult<SetVariableResponse> executionResult = terminal.getManage().setVariable(setVariableRequest);
          POSLinkManage.ManageSetVariableResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkManage.ManageSetVariableResponse.class);
          } else {
            rsp = new POSLinkManage.ManageSetVariableResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void inputAccount(@NonNull POSLinkManage.ManageInputAccountRequest req, POSLinkManage.Result<POSLinkManage.ManageInputAccountResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkManage.ManageInputAccountResponse rsp = new POSLinkManage.ManageInputAccountResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          InputAccountRequest inputAccountRequest = jsonTransform(req, InputAccountRequest.class);
          ExecutionResult<InputAccountResponse> executionResult = terminal.getManage().inputAccount(inputAccountRequest);
          POSLinkManage.ManageInputAccountResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkManage.ManageInputAccountResponse.class);
          } else {
            rsp = new POSLinkManage.ManageInputAccountResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void getVariable(@NonNull POSLinkManage.ManageGetVariableRequest req, POSLinkManage.Result<POSLinkManage.ManageGetVariableResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkManage.ManageGetVariableResponse rsp = new POSLinkManage.ManageGetVariableResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          GetVariableRequest getVariableRequest = jsonTransform(req, GetVariableRequest.class);
          ExecutionResult<GetVariableResponse> executionResult = terminal.getManage().getVariable(getVariableRequest);
          POSLinkManage.ManageGetVariableResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkManage.ManageGetVariableResponse.class);
          } else {
            rsp = new POSLinkManage.ManageGetVariableResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }
    });

    POSLinkPayload.POSLinkPayloadApi.setup(binaryMessenger, new POSLinkPayload.POSLinkPayloadApi() {
      @Override
      public void payload(@NonNull POSLinkPayload.PayloadPayloadRequest req, POSLinkPayload.Result<POSLinkPayload.PayloadPayloadResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkPayload.PayloadPayloadResponse rsp = new POSLinkPayload.PayloadPayloadResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          PayloadRequest payloadRequest = jsonTransform(req, PayloadRequest.class);
          ExecutionResult<PayloadResponse> executionResult = terminal.getPayload().payload(payloadRequest);
          POSLinkPayload.PayloadPayloadResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkPayload.PayloadPayloadResponse.class);
          } else {
            rsp = new POSLinkPayload.PayloadPayloadResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }
    });

    POSLinkPed.POSLinkPedApi.setup(binaryMessenger, new POSLinkPed.POSLinkPedApi() {
      @Override
      public void sessionKeyInjection(@NonNull POSLinkPed.PedSessionKeyInjectionRequest req, POSLinkPed.Result<POSLinkPed.PedSessionKeyInjectionResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkPed.PedSessionKeyInjectionResponse rsp = new POSLinkPed.PedSessionKeyInjectionResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          SessionKeyInjectionRequest sessionKeyInjectionRequest = jsonTransform(req, SessionKeyInjectionRequest.class);
          ExecutionResult<SessionKeyInjectionResponse> executionResult = terminal.getPed().sessionKeyInjection(sessionKeyInjectionRequest);
          POSLinkPed.PedSessionKeyInjectionResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkPed.PedSessionKeyInjectionResponse.class);
          } else {
            rsp = new POSLinkPed.PedSessionKeyInjectionResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void increaseKsn(@NonNull POSLinkPed.PedIncreaseKsnRequest req, POSLinkPed.Result<POSLinkPed.PedIncreaseKsnResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkPed.PedIncreaseKsnResponse rsp = new POSLinkPed.PedIncreaseKsnResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          IncreaseKsnRequest increaseKsnRequest = jsonTransform(req, IncreaseKsnRequest.class);
          ExecutionResult<IncreaseKsnResponse> executionResult = terminal.getPed().increaseKsn(increaseKsnRequest);
          POSLinkPed.PedIncreaseKsnResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkPed.PedIncreaseKsnResponse.class);
          } else {
            rsp = new POSLinkPed.PedIncreaseKsnResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void getPedInformation(@NonNull POSLinkPed.PedGetPedInformationRequest req, POSLinkPed.Result<POSLinkPed.PedGetPedInformationResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkPed.PedGetPedInformationResponse rsp = new POSLinkPed.PedGetPedInformationResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          GetPedInformationRequest getPedInfoRequest = jsonTransform(req, GetPedInformationRequest.class);
          ExecutionResult<GetPedInformationResponse> executionResult = terminal.getPed().getPedInformation(getPedInfoRequest);
          POSLinkPed.PedGetPedInformationResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkPed.PedGetPedInformationResponse.class);
          } else {
            rsp = new POSLinkPed.PedGetPedInformationResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void macCalculation(@NonNull POSLinkPed.PedMacCalculationRequest req, POSLinkPed.Result<POSLinkPed.PedMacCalculationResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkPed.PedMacCalculationResponse rsp = new POSLinkPed.PedMacCalculationResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          MacCalculationRequest macCalculationRequest = jsonTransform(req, MacCalculationRequest.class);
          ExecutionResult<MacCalculationResponse> executionResult = terminal.getPed().macCalculation(macCalculationRequest);
          POSLinkPed.PedMacCalculationResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkPed.PedMacCalculationResponse.class);
          } else {
            rsp = new POSLinkPed.PedMacCalculationResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }
    });

    POSLinkBatch.POSLinkBatchApi.setup(binaryMessenger, new POSLinkBatch.POSLinkBatchApi() {
      @Override
      public void safUpload(@NonNull POSLinkBatch.BatchSafUploadRequest req, POSLinkBatch.Result<POSLinkBatch.BatchSafUploadResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkBatch.BatchSafUploadResponse rsp = new POSLinkBatch.BatchSafUploadResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          SafUploadRequest safUploadRequest = jsonTransform(req, SafUploadRequest.class);
          ExecutionResult<SafUploadResponse> executionResult = terminal.getBatch().safUpload(safUploadRequest);
          POSLinkBatch.BatchSafUploadResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkBatch.BatchSafUploadResponse.class);
          } else {
            rsp = new POSLinkBatch.BatchSafUploadResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void purgeBatch(@NonNull POSLinkBatch.BatchPurgeBatchRequest req, POSLinkBatch.Result<POSLinkBatch.BatchPurgeBatchResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkBatch.BatchPurgeBatchResponse rsp = new POSLinkBatch.BatchPurgeBatchResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          PurgeBatchRequest purgeBatchRequest = jsonTransform(req, PurgeBatchRequest.class);
          ExecutionResult<PurgeBatchResponse> executionResult = terminal.getBatch().purgeBatch(purgeBatchRequest);
          POSLinkBatch.BatchPurgeBatchResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkBatch.BatchPurgeBatchResponse.class);
          } else {
            rsp = new POSLinkBatch.BatchPurgeBatchResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void batchClose(@NonNull POSLinkBatch.BatchBatchCloseRequest req, POSLinkBatch.Result<POSLinkBatch.BatchBatchCloseResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkBatch.BatchBatchCloseResponse rsp = new POSLinkBatch.BatchBatchCloseResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          BatchCloseRequest batchCloseRequest = jsonTransform(req, BatchCloseRequest.class);
          ExecutionResult<BatchCloseResponse> executionResult = terminal.getBatch().batchClose(batchCloseRequest);
          POSLinkBatch.BatchBatchCloseResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkBatch.BatchBatchCloseResponse.class);
          } else {
            rsp = new POSLinkBatch.BatchBatchCloseResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void batchClear(@NonNull POSLinkBatch.BatchBatchClearRequest req, POSLinkBatch.Result<POSLinkBatch.BatchBatchClearResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkBatch.BatchBatchClearResponse rsp = new POSLinkBatch.BatchBatchClearResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          BatchClearRequest batchClearRequest = jsonTransform(req, BatchClearRequest.class);
          ExecutionResult<BatchClearResponse> executionResult = terminal.getBatch().batchClear(batchClearRequest);
          POSLinkBatch.BatchBatchClearResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkBatch.BatchBatchClearResponse.class);
          } else {
            rsp = new POSLinkBatch.BatchBatchClearResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void deleteSafFile(@NonNull POSLinkBatch.BatchDeleteSafFileRequest req, POSLinkBatch.Result<POSLinkBatch.BatchDeleteSafFileResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkBatch.BatchDeleteSafFileResponse rsp = new POSLinkBatch.BatchDeleteSafFileResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          DeleteSafFileRequest deleteSafFileRequest = jsonTransform(req, DeleteSafFileRequest.class);
          ExecutionResult<DeleteSafFileResponse> executionResult = terminal.getBatch().deleteSafFile(deleteSafFileRequest);
          POSLinkBatch.BatchDeleteSafFileResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkBatch.BatchDeleteSafFileResponse.class);
          } else {
            rsp = new POSLinkBatch.BatchDeleteSafFileResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void forceBatchClose(@NonNull POSLinkBatch.BatchForceBatchCloseRequest req, POSLinkBatch.Result<POSLinkBatch.BatchForceBatchCloseResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkBatch.BatchForceBatchCloseResponse rsp = new POSLinkBatch.BatchForceBatchCloseResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          ForceBatchCloseRequest forceBatchCloseRequest = jsonTransform(req, ForceBatchCloseRequest.class);
          ExecutionResult<ForceBatchCloseResponse> executionResult = terminal.getBatch().forceBatchClose(forceBatchCloseRequest);
          POSLinkBatch.BatchForceBatchCloseResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkBatch.BatchForceBatchCloseResponse.class);
          } else {
            rsp = new POSLinkBatch.BatchForceBatchCloseResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void deleteTransaction(@NonNull POSLinkBatch.BatchDeleteTransactionRequest req, POSLinkBatch.Result<POSLinkBatch.BatchDeleteTransactionResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkBatch.BatchDeleteTransactionResponse rsp = new POSLinkBatch.BatchDeleteTransactionResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          DeleteTransactionRequest deleteTransactionRequest = jsonTransform(req, DeleteTransactionRequest.class);
          ExecutionResult<DeleteTransactionResponse> executionResult = terminal.getBatch().deleteTransaction(deleteTransactionRequest);
          POSLinkBatch.BatchDeleteTransactionResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkBatch.BatchDeleteTransactionResponse.class);
          } else {
            rsp = new POSLinkBatch.BatchDeleteTransactionResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }
    });

    POSLinkReport.POSLinkReportApi.setup(binaryMessenger, new POSLinkReport.POSLinkReportApi() {
      @Override
      public void hostDetailReport(@NonNull POSLinkReport.ReportHostDetailReportRequest req, POSLinkReport.Result<POSLinkReport.ReportHostDetailReportResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkReport.ReportHostDetailReportResponse rsp = new POSLinkReport.ReportHostDetailReportResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          HostDetailReportRequest hostDetailReportRequest = jsonTransform(req, HostDetailReportRequest.class);
          ExecutionResult<HostDetailReportResponse> executionResult = terminal.getReport().hostDetailReport(hostDetailReportRequest);
          POSLinkReport.ReportHostDetailReportResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkReport.ReportHostDetailReportResponse.class);
          } else {
            rsp = new POSLinkReport.ReportHostDetailReportResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void localTotalReport(@NonNull POSLinkReport.ReportLocalTotalReportRequest req, POSLinkReport.Result<POSLinkReport.ReportLocalTotalReportResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkReport.ReportLocalTotalReportResponse rsp = new POSLinkReport.ReportLocalTotalReportResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          LocalTotalReportRequest localTotalReportRequest = jsonTransform(req, LocalTotalReportRequest.class);
          ExecutionResult<LocalTotalReportResponse> executionResult = terminal.getReport().localTotalReport(localTotalReportRequest);
          POSLinkReport.ReportLocalTotalReportResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkReport.ReportLocalTotalReportResponse.class);
          } else {
            rsp = new POSLinkReport.ReportLocalTotalReportResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void localDetailReport(@NonNull POSLinkReport.ReportLocalDetailReportRequest req, POSLinkReport.Result<POSLinkReport.ReportLocalDetailReportResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkReport.ReportLocalDetailReportResponse rsp = new POSLinkReport.ReportLocalDetailReportResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          LocalDetailReportRequest localDetailReportRequest = jsonTransform(req, LocalDetailReportRequest.class);
          ExecutionResult<LocalDetailReportResponse> executionResult = terminal.getReport().localDetailReport(localDetailReportRequest);
          POSLinkReport.ReportLocalDetailReportResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkReport.ReportLocalDetailReportResponse.class);
          } else {
            rsp = new POSLinkReport.ReportLocalDetailReportResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void safSummaryReport(@NonNull POSLinkReport.ReportSafSummaryReportRequest req, POSLinkReport.Result<POSLinkReport.ReportSafSummaryReportResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkReport.ReportSafSummaryReportResponse rsp = new POSLinkReport.ReportSafSummaryReportResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          SafSummaryReportRequest safSummaryReportRequest = jsonTransform(req, SafSummaryReportRequest.class);
          ExecutionResult<SafSummaryReportResponse> executionResult = terminal.getReport().safSummaryReport(safSummaryReportRequest);
          POSLinkReport.ReportSafSummaryReportResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkReport.ReportSafSummaryReportResponse.class);
          } else {
            rsp = new POSLinkReport.ReportSafSummaryReportResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void localFailedReport(@NonNull POSLinkReport.ReportLocalFailedReportRequest req, POSLinkReport.Result<POSLinkReport.ReportLocalFailedReportResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkReport.ReportLocalFailedReportResponse rsp = new POSLinkReport.ReportLocalFailedReportResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          LocalFailedReportRequest localFailedReportRequest = jsonTransform(req, LocalFailedReportRequest.class);
          ExecutionResult<LocalFailedReportResponse> executionResult = terminal.getReport().localFailedReport(localFailedReportRequest);
          POSLinkReport.ReportLocalFailedReportResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkReport.ReportLocalFailedReportResponse.class);
          } else {
            rsp = new POSLinkReport.ReportLocalFailedReportResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void historyReport(@NonNull POSLinkReport.ReportHistoryReportRequest req, POSLinkReport.Result<POSLinkReport.ReportHistoryReportResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkReport.ReportHistoryReportResponse rsp = new POSLinkReport.ReportHistoryReportResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          HistoryReportRequest historyReportRequest = jsonTransform(req, HistoryReportRequest.class);
          ExecutionResult<HistoryReportResponse> executionResult = terminal.getReport().historyReport(historyReportRequest);
          POSLinkReport.ReportHistoryReportResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkReport.ReportHistoryReportResponse.class);
          } else {
            rsp = new POSLinkReport.ReportHistoryReportResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void hostReport(@NonNull POSLinkReport.ReportHostReportRequest req, POSLinkReport.Result<POSLinkReport.ReportHostReportResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkReport.ReportHostReportResponse rsp = new POSLinkReport.ReportHostReportResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          HostReportRequest hostReportRequest = jsonTransform(req, HostReportRequest.class);
          ExecutionResult<HostReportResponse> executionResult = terminal.getReport().hostReport(hostReportRequest);
          POSLinkReport.ReportHostReportResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkReport.ReportHostReportResponse.class);
          } else {
            rsp = new POSLinkReport.ReportHostReportResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }
    });

    POSLinkTransaction.POSLinkTransactionApi.setup(binaryMessenger, new POSLinkTransaction.POSLinkTransactionApi() {
      @Override
      public void doEbt(@NonNull POSLinkTransaction.TransactionDoEbtRequest req, POSLinkTransaction.Result<POSLinkTransaction.TransactionDoEbtResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkTransaction.TransactionDoEbtResponse rsp = new POSLinkTransaction.TransactionDoEbtResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          DoEbtRequest doEbtRequest = jsonTransform(req, DoEbtRequest.class);
          ExecutionResult<DoEbtResponse> executionResult = terminal.getTransaction().doEbt(doEbtRequest);
          POSLinkTransaction.TransactionDoEbtResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkTransaction.TransactionDoEbtResponse.class);
          } else {
            rsp = new POSLinkTransaction.TransactionDoEbtResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void doCredit(@NonNull POSLinkTransaction.TransactionDoCreditRequest req, POSLinkTransaction.Result<POSLinkTransaction.TransactionDoCreditResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkTransaction.TransactionDoCreditResponse rsp = new POSLinkTransaction.TransactionDoCreditResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          DoCreditRequest doCreditRequest = jsonTransform(req, DoCreditRequest.class);
          ExecutionResult<DoCreditResponse> executionResult = terminal.getTransaction().doCredit(doCreditRequest);
          POSLinkTransaction.TransactionDoCreditResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkTransaction.TransactionDoCreditResponse.class);
          } else {
            rsp = new POSLinkTransaction.TransactionDoCreditResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void doLoyalty(@NonNull POSLinkTransaction.TransactionDoLoyaltyRequest req, POSLinkTransaction.Result<POSLinkTransaction.TransactionDoLoyaltyResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkTransaction.TransactionDoLoyaltyResponse rsp = new POSLinkTransaction.TransactionDoLoyaltyResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          DoLoyaltyRequest doLoyaltyRequest = jsonTransform(req, DoLoyaltyRequest.class);
          ExecutionResult<DoLoyaltyResponse> executionResult = terminal.getTransaction().doLoyalty(doLoyaltyRequest);
          POSLinkTransaction.TransactionDoLoyaltyResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkTransaction.TransactionDoLoyaltyResponse.class);
          } else {
            rsp = new POSLinkTransaction.TransactionDoLoyaltyResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void doCheck(@NonNull POSLinkTransaction.TransactionDoCheckRequest req, POSLinkTransaction.Result<POSLinkTransaction.TransactionDoCheckResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkTransaction.TransactionDoCheckResponse rsp = new POSLinkTransaction.TransactionDoCheckResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          DoCheckRequest doCheckRequest = jsonTransform(req, DoCheckRequest.class);
          ExecutionResult<DoCheckResponse> executionResult = terminal.getTransaction().doCheck(doCheckRequest);
          POSLinkTransaction.TransactionDoCheckResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkTransaction.TransactionDoCheckResponse.class);
          } else {
            rsp = new POSLinkTransaction.TransactionDoCheckResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void doCash(@NonNull POSLinkTransaction.TransactionDoCashRequest req, POSLinkTransaction.Result<POSLinkTransaction.TransactionDoCashResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkTransaction.TransactionDoCashResponse rsp = new POSLinkTransaction.TransactionDoCashResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          DoCashRequest doCashRequest = jsonTransform(req, DoCashRequest.class);
          ExecutionResult<DoCashResponse> executionResult = terminal.getTransaction().doCash(doCashRequest);
          POSLinkTransaction.TransactionDoCashResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkTransaction.TransactionDoCashResponse.class);
          } else {
            rsp = new POSLinkTransaction.TransactionDoCashResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void doGift(@NonNull POSLinkTransaction.TransactionDoGiftRequest req, POSLinkTransaction.Result<POSLinkTransaction.TransactionDoGiftResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkTransaction.TransactionDoGiftResponse rsp = new POSLinkTransaction.TransactionDoGiftResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          DoGiftRequest doGiftRequest = jsonTransform(req, DoGiftRequest.class);
          ExecutionResult<DoGiftResponse> executionResult = terminal.getTransaction().doGift(doGiftRequest);
          POSLinkTransaction.TransactionDoGiftResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkTransaction.TransactionDoGiftResponse.class);
          } else {
            rsp = new POSLinkTransaction.TransactionDoGiftResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }

      @Override
      public void doDebit(@NonNull POSLinkTransaction.TransactionDoDebitRequest req, POSLinkTransaction.Result<POSLinkTransaction.TransactionDoDebitResponse> result) {
        new Thread(() -> {
          terminal = POSLinkSemi.getInstance().getTerminal(currentActivity, commSetting);
          if (terminal == null) {
            POSLinkTransaction.TransactionDoDebitResponse rsp = new POSLinkTransaction.TransactionDoDebitResponse();
            rsp.setResponseCode("-1");
            rsp.setResponseMessage("Init Failed");
            result.success(rsp);
            return;
          }
          setReportStatusListener(terminal);
          DoDebitRequest doDebitRequest = jsonTransform(req, DoDebitRequest.class);
          ExecutionResult<DoDebitResponse> executionResult = terminal.getTransaction().doDebit(doDebitRequest);
          POSLinkTransaction.TransactionDoDebitResponse rsp;
          if (executionResult.isSuccessful() && executionResult.response() != null) {
            rsp = jsonTransform(executionResult.response(), POSLinkTransaction.TransactionDoDebitResponse.class);
          } else {
            rsp = new POSLinkTransaction.TransactionDoDebitResponse();
            rsp.setResponseCode(executionResult.code() + "");
            rsp.setResponseMessage(executionResult.message());
          }
          currentActivity.runOnUiThread(() -> {
            result.success(rsp);
          });
        }).start();
      }
    });
  }

  private void setReportStatusListener(Terminal terminal) {
    terminal.setReportStatusListener(new ReportStatusListener() {
      @Override
      public void onReportStatus(int i) {
        currentActivity.runOnUiThread(new Runnable() {
          @Override
          public void run() {
            Toast.makeText(context, "Status:" + String.valueOf(i), Toast.LENGTH_LONG).show();
          }
        });
      }
    });
  }


  private <T> T jsonTransform(Object input, Class<T> classOfT) {
    Gson gson = new GsonBuilder()
            .registerTypeHierarchyAdapter(Enum.class, new JsonSerializer<Enum<?>>() {
              @Override
              public JsonElement serialize(Enum<?> src, Type typeOfSrc, JsonSerializationContext context) {
                // 使用 ordinal 序列化成基本数据类型
                return new JsonPrimitive(src.name());
              }

            })
            .registerTypeHierarchyAdapter(Enum.class, new JsonDeserializer<Enum<?>>() {
              @Override
              public Enum<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                try {
                  // 必须是基本数据类型
                  if (json.isJsonPrimitive()) {

                    JsonPrimitive jsonPrimitive = json.getAsJsonPrimitive();

                    // 反射读取所有得枚举实例
                    String name;
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                      name = typeOfT.getTypeName();
                    } else {
                      name = typeOfT.toString().split(" ")[1];
                    }
                    Enum<?>[] enumConstants = (Enum<?>[]) Class.forName(name).getEnumConstants();

                    if (jsonPrimitive.isNumber()) { // 数字
                      return enumConstants[jsonPrimitive.getAsInt()];
                    } else if (jsonPrimitive.isString()) { // 字符串
                      String val = jsonPrimitive.getAsString();
                      for (Enum<?> constant : enumConstants) {
                        String constantName = constant.name();
                        if (constantName.replace("_", "").equalsIgnoreCase(val.replace("_", ""))) {
                          return constant;
                        }
                      }
                    }
                  }
                } catch (ClassNotFoundException | ArrayIndexOutOfBoundsException e) {
                  e.printStackTrace();
                }
                throw new IllegalArgumentException("bad param:" + json.getAsString());
              }
            })
            .create();
    String jsonStr = gson.toJson(input);
    return gson.fromJson(jsonStr, classOfT);
  }
}
